//////////////////////////////////////////////////////////////////////
//
//	Crytek Source code
// 
//	File: System.cpp
//  Description: CryENGINE system core-handle all subsystems
// 
//	History:
//	-Jan 31,2001: Originally Created by Marco Corbetta
//	-: modified by all
//
//////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include "System.h"
#include <time.h>
//#include "ini_vars.h"
#include "CryLibrary.h"






#if defined(_RELEASE) && (defined(PS3) || defined(XENON) || defined(gringo) || defined(CAFE))
	//exclude some not needed functionality for release console builds
	#define EXCLUDE_UPDATE_ON_CONSOLE
#endif

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
	// If app hasn't choosen, set to work with Windows 98, Windows Me, Windows 2000, Windows XP and beyond
#include <windows.h>
#endif

#include <INetwork.h>
#include <I3DEngine.h>
#include <IAISystem.h>
#include <IRenderer.h>
#include <ICryPak.h>
#include <IMovieSystem.h>
#include <IEntitySystem.h>
#include <IInput.h>
#include <ILog.h>
#include <ISound.h>
#include <IReverbManager.h>
#include <IMusicSystem.h>
#include "NullImplementation/NULLSoundSystem.h"
#include <ICryAnimation.h>
#include <IScriptSystem.h>
#include <IProcess.h>
#include <IBudgetingSystem.h>
#include <IGame.h>
#include <IGameFramework.h>
#include <INotificationNetwork.h>
#include <ICodeCheckpointMgr.h>
#include <ISoftCodeMgr.h>
#include "TestSystemLegacy.h"							// CTestSystem
#include "VisRegTest.h"

#include "CryPak.h"
#include "XConsole.h"
#include "Telemetry/TelemetrySystem.h"
#include "Telemetry/TelemetryFileStream.h"
#include "Telemetry/TelemetryUDPStream.h"
#include "Log.h"
#include "CrySizerStats.h"
#include "CrySizerImpl.h"
#include "NotificationNetwork.h"
#include "ProfileLog.h"

#include "XML/xml.h"
#include "XML/ReadWriteXMLSink.h"
#include "DataProbe.h"

#include "StreamEngine/StreamEngine.h"
#include "PhysRenderer.h"

#include "LocalizedStringManager.h"
#include "XML/XmlUtils.h"
#include "ThreadProfiler.h"
#include "IDiskProfiler.h"
#include "SystemEventDispatcher.h"
#include "HardwareMouse.h"
#include "ServerThrottle.h"
#include "ILocalMemoryUsage.h"
#include "ResourceManager.h"
#include "MemoryManager.h"
#include "LoadingProfiler.h"
#include "IScaleformGFx.h"

#include "IZLibCompressor.h"
#include "zlib/zlib.h"
#include "RemoteConsole/RemoteConsole.h"

#include <crc32.h>
#include <PNoise3.h>
#include <StringUtils.h>

#include "CryWaterMark.h"
WATERMARKDATA(_m);

#ifdef WIN32
#define  PROFILE_WITH_VTUNE
#include <process.h>
#include <malloc.h>
#endif

// profilers api.
VTuneFunction VTResume = NULL;
VTuneFunction VTPause = NULL;

// Define global cvars.
SSystemCVars g_cvars;

#include "ITextModeConsole.h"

extern int CryMemoryGetAllocatedSize();

// these heaps are used by underlying System structures
// to allocate, accordingly, small (like elements of std::set<..*>) and big (like memory for reading files) objects
// hopefully someday we'll have standard MT-safe heap
//CMTSafeHeap g_pakHeap;
CMTSafeHeap* g_pPakHeap = 0;// = &g_pakHeap;

#if EMBED_PHYSICS_AS_FIBER
# define SWITCH_TO_PHYSFIBER(x) { if ((x) != NULL) JobManager::Fiber::SwitchToFiber((x)); } 
# define YIELD_PHYSFIBER() { JobManager::Fiber::YieldFiber(); } 
#else 
# define SWITCH_TO_PHYSFIBER(x) 
# define YIELD_PHYSFIBER() { Sleep(0); } 
#endif 

//////////////////////////////////////////////////////////////////////////
#include "Validator.h"

#include "../CryAction/IViewSystem.h"
















































/////////////////////////////////////////////////////////////////////////////////
// System Implementation.
//////////////////////////////////////////////////////////////////////////

#if !defined(PS3)
	SSystemGlobalEnvironment CSystem::m_env;
#endif

CSystem::CSystem() 



{
	m_iHeight = 0;
	m_iWidth = 0;
	m_iColorBits = 0;
	// CRT ALLOCATION threshold

	m_pSystemEventDispatcher = new CSystemEventDispatcher(); // Must be first.

	//#ifndef _XBOX
#ifdef WIN32	
	m_hInst = NULL;
	m_hWnd = NULL;
#if _MSC_VER < 1000
	int sbh = _set_sbh_threshold(1016);
#endif
#endif

	//////////////////////////////////////////////////////////////////////////
	// Clear environment.
	//////////////////////////////////////////////////////////////////////////
	memset( &m_env,0,sizeof(m_env) );

	//////////////////////////////////////////////////////////////////////////
	// Reset handles.
	memset( &m_dll,0,sizeof(m_dll) );
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	// Initialize global environment interface pointers.
	m_env.pSystem = this;
	m_env.pTimer = &m_Time;
	m_env.pNameTable = &m_nameTable;
	m_env.pFrameProfileSystem = &m_FrameProfileSystem;
	m_env.bServer = false;
#ifndef CAFE
	m_env.bMultiplayer = false;
	m_env.bHostMigrating = false;
#endif
	m_env.bProfilerEnabled = false;
	m_env.callbackStartSection = 0;
	m_env.callbackEndSection = 0;
	m_env.bIgnoreAllAsserts = false;
	m_env.bNoAssertDialog = false;
	m_env.bTesting = false;

	m_env.SetFMVIsPlaying(false);

	m_env.szDebugStatus[0] = '\0';

#if !defined(XENON) && !defined(PS3) && !defined(gringo)
	m_env.SetIsClient(false);
#endif
	//////////////////////////////////////////////////////////////////////////
	
	m_pStreamEngine = NULL;
	m_PhysThread = 0;
#if EMBED_PHYSICS_AS_FIBER
	m_PhysFiber = NULL; 
#endif 

	m_pTelemetryFileStream	= NULL;
	m_pTelemetryUDPStream		= NULL;

	m_pIFont = NULL;
	m_pTestSystem = NULL;
	m_pVisRegTest = NULL;
	m_rWidth=NULL;
	m_rHeight=NULL;
	m_rColorBits=NULL;
	m_rDepthBits=NULL;
	m_cvSSInfo=NULL;
	m_rStencilBits=NULL;
	m_rFullscreen=NULL;
	m_rDriver=NULL;
	m_sysNoUpdate=NULL;
	m_pMemoryManager = NULL;
	m_pProcess = NULL;
	
	m_pValidator = NULL;
	m_pCmdLine = NULL;
	m_pDefaultValidator = NULL;
	m_pIBudgetingSystem = NULL;
	m_pIZLibCompressor = NULL;
	m_pLocalizationManager = NULL;
	m_pNULLSoundSystem = NULL;
	m_sys_physics_CPU=0;



	m_sys_min_step=0;
	m_sys_max_step=0;

	m_pNotificationNetwork = NULL;

	m_cvAIUpdate = NULL;

	m_pUserCallback = NULL;
	m_sys_memory_debug=NULL;
	m_sysWarnings = NULL;
	m_sysKeyboard = NULL;
	m_sys_profile = NULL;
	m_sys_profile_additionalsub = NULL;
	m_sys_profile_graphScale = NULL;
	m_sys_profile_pagefaultsgraph = NULL;
	m_sys_profile_graph = NULL;
	m_sys_profile_filter = NULL;
	m_sys_profile_filter_thread = NULL;
	m_sys_profile_allThreads = NULL;
	m_sys_profile_network = NULL;
	m_sys_profile_peak = NULL;
	m_sys_profile_peak_time = NULL;
	m_sys_profile_memory = NULL;
	m_sys_profile_sampler = NULL;
	m_sys_profile_sampler_max_samples = NULL;
	m_sys_spu_enable = NULL;
	m_sys_spu_profile = NULL;
	m_sys_spu_max = NULL;
//	m_sys_spu_flipmode = NULL;
	m_sys_spu_debug = NULL;
	m_sys_job_system_filter = NULL;
	m_sys_job_system_enable = NULL;
	m_sys_job_system_profiler = NULL;
	m_sys_job_system_max_worker = NULL;
	m_sys_spu_dump_stats = NULL;




	m_sys_spu_streaming = NULL;
	m_sys_spec = NULL;
	m_sys_firstlaunch = NULL;
	m_sys_enable_budgetmonitoring = NULL;
	m_sys_preload = NULL;









//	m_sys_filecache = NULL;
	m_pCpu = NULL;
	m_sys_game_folder = NULL;

	
	m_bQuit = false;
	m_bRelaunch = false;
	m_iLoadingMode = 0;
	m_bTestMode = false;
	m_bEditor = false;
	m_bPreviewMode = false;
	m_bIgnoreUpdates = false;
	m_bNoCrashDialog = false;

	m_nStrangeRatio = 1000;
	// no mem stats at the moment
	m_pMemStats = NULL;
	m_pSizer = NULL;

	m_pCVarQuit = NULL;

	m_pDownloadManager = 0;
	// default game MOD is root
	memset(m_szGameMOD,0,256);
	m_pDataProbe = 0;
#if defined( _DATAPROBE )
	m_pDataProbe = new CDataProbe;
#endif
	m_bForceNonDevMode=false;
	m_bWasInDevMode = false;
	m_bInDevMode = false;
	m_bGameFolderWritable = false;

	m_nServerConfigSpec = CONFIG_VERYHIGH_SPEC;
	m_nMaxConfigSpec = CONFIG_PS3;

	//m_hPhysicsThread = INVALID_HANDLE_VALUE;
	//m_hPhysicsActive = INVALID_HANDLE_VALUE;
	//m_bStopPhysics = 0;
	//m_bPhysicsActive = 0;

	m_pProgressListener = 0;

	m_bPaused = false;
	m_bNoUpdate = false;
	m_nUpdateCounter = 0;
	m_iApplicationInstance = -1;

	m_pPhysRenderer = 0;

	m_pXMLUtils = new CXmlUtils(this);
	m_pTestSystem = new CTestSystemLegacy;
	m_pMemoryManager = CryGetIMemoryManager();
	m_pThreadTaskManager = new CThreadTaskManager;
	m_pResourceManager = new CResourceManager;
	m_pUnixConsole = NULL;
	m_pThreadProfiler = 0;
	m_pDiskProfiler = NULL;

	m_pMiniGUI = NULL;
	m_pPerfHUD = NULL;

	g_pPakHeap = new CMTSafeHeap;

	m_bUIFrameworkMode = false;
	
	m_PlatformOSCreateFlags = 0;








	// create job manager
	m_env.pJobManager = GetJobManSPUInterface();
	
	m_UpdateTimesIdx = 0U; 
	m_bNeedDoWorkDuringOcclusionChecks = false;
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
CSystem::~CSystem()
{
	ShutDown();

  m_pThreadTaskManager->CloseThreads();

	FreeLib(m_dll.hNetwork);
	FreeLib(m_dll.hAI);
	FreeLib(m_dll.hInput);
	FreeLib(m_dll.hScript);
	FreeLib(m_dll.hPhysics);
	FreeLib(m_dll.hEntitySystem);
	FreeLib(m_dll.hRenderer);
	FreeLib(m_dll.hScaleform);
	FreeLib(m_dll.hFont);
	FreeLib(m_dll.hMovie);
	FreeLib(m_dll.hIndoor);
	FreeLib(m_dll.h3DEngine);
	FreeLib(m_dll.hAnimation);
	FreeLib(m_dll.hGame);
	FreeLib(m_dll.hSound);
	SAFE_DELETE(m_pVisRegTest);
	SAFE_DELETE(m_pThreadProfiler);
#if (!defined (_RELEASE) || defined(ENABLE_PROFILING_CODE))
	SAFE_DELETE(m_pDiskProfiler);	
#endif
	SAFE_DELETE(m_pDataProbe);
	SAFE_DELETE(m_pXMLUtils);
	SAFE_DELETE(m_pThreadTaskManager);
	SAFE_DELETE(m_pResourceManager);
	SAFE_DELETE(m_pSystemEventDispatcher);
//	SAFE_DELETE(m_pMemoryManager);

	SAFE_DELETE(g_pPakHeap);

	m_env.pSystem = NULL;
}

//////////////////////////////////////////////////////////////////////////
void CSystem::Release()
{
	delete this;
}

//////////////////////////////////////////////////////////////////////////
void CSystem::FreeLib( WIN_HMODULE hLibModule)
{
	if (hLibModule) 
	{ 
		CryFreeLibrary(hLibModule);
		(hLibModule)=NULL; 
	} 
}

//////////////////////////////////////////////////////////////////////////
IStreamEngine* CSystem::GetStreamEngine()
{
	return m_pStreamEngine;
}

//////////////////////////////////////////////////////////////////////////
IRemoteConsole* CSystem::GetIRemoteConsole()
{
	return CRemoteConsole::GetInst();
}

//////////////////////////////////////////////////////////////////////////
void CSystem::SetForceNonDevMode( const bool bValue )
{
	m_bForceNonDevMode=bValue;
	if (bValue)
		SetDevMode(false);
}

//////////////////////////////////////////////////////////////////////////
bool CSystem::GetForceNonDevMode() const
{
	return m_bForceNonDevMode;
}

//////////////////////////////////////////////////////////////////////////
void CSystem::SetDevMode( bool bEnable )
{
	if (bEnable)
		m_bWasInDevMode = true;
	m_bInDevMode = bEnable;
}


void LvlRes_export( IConsoleCmdArgs *pParams );

///////////////////////////////////////////////////
void CSystem::ShutDown()
{		
	CryLogAlways("System Shutdown");

	// TODO: cleanup -RL
	//m_bQuit=true;

	m_FrameProfileSystem.Enable(false,false);

	CLoadingProfilerSystem::ShutDown();

	if (m_pUserCallback)
		m_pUserCallback->OnShutdown();

	GetIRemoteConsole()->Stop();

	SAFE_DELETE(m_pUnixConsole);

#if !EMBED_PHYSICS_AS_FIBER
	KillPhysicsThread();
#else
	KillPhysicsFiber();
#endif 
	
	if (m_env.pSoundSystem && m_env.pSoundSystem->GetIReverbManager())
	{
		// turn EAX off otherwise it affects all Windows sounds!
		m_env.pSoundSystem->GetIReverbManager()->SetListenerReverb(REVERB_PRESET_OFF);
	}

	m_FrameProfileSystem.Done();

	if (m_sys_firstlaunch)
		m_sys_firstlaunch->Set( "0" );

	if (m_bEditor)
	{
		// restore the old saved cvars
		if(m_env.pConsole->GetCVar("r_Width"))
			m_env.pConsole->GetCVar("r_Width")->Set(m_iWidth);
		if(m_env.pConsole->GetCVar("r_Height"))
			m_env.pConsole->GetCVar("r_Height")->Set(m_iHeight);
		if(m_env.pConsole->GetCVar("r_ColorBits"))
			m_env.pConsole->GetCVar("r_ColorBits")->Set(m_iColorBits);
	}

	if (m_bEditor && !m_bRelaunch)
	{
		SaveConfiguration();
	}

	//if (!m_bEditor && !bRelaunch)
#if !defined(XENON) && !defined(PS3) && !defined(gringo) && !defined(CAFE)
	if (!m_bEditor)
	{	 		
		if (m_pCVarQuit && m_pCVarQuit->GetIVal())		
		{
			SaveConfiguration();

			if (m_env.pNetwork != NULL)
			{
				m_env.pNetwork->FastShutdown();
			}

			//@TODO: release game.
			//SAFE_RELEASE(m_env.pGame);
			//FreeLib(m_dll.hGame);

			SAFE_RELEASE(m_env.pRenderer);
			FreeLib(m_dll.hRenderer);
	
			SAFE_RELEASE(m_env.pProfileLogSystem);
			SAFE_RELEASE(m_env.pLog);		// creates log backup

			if (m_env.pGame)
			m_env.pGame->Shutdown();
			return; //safe clean return
		}
	}
#endif//XENON && PS3

	//////////////////////////////////////////////////////////////////////////
	// Release Game.
	//////////////////////////////////////////////////////////////////////////	
	if (m_env.pEntitySystem)
	  m_env.pEntitySystem->Unload();
	//@TODO: Release game.
	//SAFE_RELEASE(m_env.pGame); 
	if (m_env.pPhysicalWorld)
	{
		m_env.pPhysicalWorld->SetPhysicsStreamer(0);
		m_env.pPhysicalWorld->SetPhysicsEventClient(0);
	}

#ifndef EXCLUDE_SCALEFORM_SDK
	if (m_env.pRenderer)
		m_env.pRenderer->FlushRTCommands(true, true, true);
	if ( m_env.pScaleformGFx )
	{
		m_env.pScaleformGFx->Release();
		m_env.pScaleformGFx = 0;
	}
#endif

	// Shutdown resource manager.
	m_pResourceManager->Shutdown();

	SAFE_RELEASE(m_env.pHardwareMouse);
	SAFE_RELEASE(m_env.pMovieSystem);
	SAFE_RELEASE(m_env.pAISystem);
	SAFE_RELEASE(m_env.pEntitySystem);
	SAFE_RELEASE(m_env.pCryFont);
	SAFE_RELEASE(m_env.pMusicSystem);
	SAFE_RELEASE(m_env.pNetwork);
//	SAFE_RELEASE(m_env.pCharacterManager);
	SAFE_RELEASE(m_env.p3DEngine);
	SAFE_RELEASE(m_env.pPhysicalWorld);
  if (m_env.pConsole)
    ((CXConsole*)m_env.pConsole)->FreeRenderResources();
	SAFE_RELEASE(m_pIZLibCompressor);
	SAFE_RELEASE(m_pIBudgetingSystem);
	SAFE_RELEASE(m_env.pRenderer);
	SAFE_RELEASE(m_env.pSoundSystem);
	SAFE_RELEASE(m_pNULLSoundSystem);
	SAFE_RELEASE(m_env.pCodeCheckpointMgr);

	if(m_env.pLog)
		m_env.pLog->UnregisterConsoleVariables();

	GetIRemoteConsole()->UnregisterConsoleVariables();

	// Release console variables.
	
	SAFE_RELEASE(m_pCVarQuit);
	SAFE_RELEASE(m_rWidth);
	SAFE_RELEASE(m_rHeight);
	SAFE_RELEASE(m_rColorBits);
	SAFE_RELEASE(m_rDepthBits);
	SAFE_RELEASE(m_cvSSInfo);
	SAFE_RELEASE(m_rStencilBits);
	SAFE_RELEASE(m_rFullscreen);
	SAFE_RELEASE(m_rDriver);

	SAFE_RELEASE(m_sysWarnings);
	SAFE_RELEASE(m_sysKeyboard);
	SAFE_RELEASE(m_sys_profile);
	SAFE_RELEASE(m_sys_profile_additionalsub);
	SAFE_RELEASE(m_sys_profile_graph);
	SAFE_RELEASE(m_sys_profile_pagefaultsgraph);
	SAFE_RELEASE(m_sys_profile_graphScale);
	SAFE_RELEASE(m_sys_profile_filter);
	SAFE_RELEASE(m_sys_profile_filter_thread);
	SAFE_RELEASE(m_sys_profile_allThreads);
	SAFE_RELEASE(m_sys_profile_network);
	SAFE_RELEASE(m_sys_profile_peak);
	SAFE_RELEASE(m_sys_profile_peak_time);
	SAFE_RELEASE(m_sys_profile_memory);
	SAFE_RELEASE(m_sys_profile_sampler);
	SAFE_RELEASE(m_sys_profile_sampler_max_samples);
	SAFE_RELEASE(m_sys_spu_enable);
	SAFE_RELEASE(m_sys_spu_profile);
	SAFE_RELEASE(m_sys_spu_max);
//	SAFE_RELEASE(m_sys_spu_flipmode);
	SAFE_RELEASE(m_sys_spu_debug);
	SAFE_RELEASE(m_sys_job_system_filter);
	SAFE_RELEASE(m_sys_job_system_enable);	
	SAFE_RELEASE(m_sys_job_system_profiler);	
	SAFE_RELEASE(m_sys_job_system_max_worker);		
	SAFE_RELEASE(m_sys_spu_dump_stats);




	SAFE_RELEASE(m_sys_spu_streaming);
	SAFE_RELEASE(m_sys_spec);
	SAFE_RELEASE(m_sys_firstlaunch);
	SAFE_RELEASE(m_sys_enable_budgetmonitoring);
	SAFE_RELEASE(m_sys_physics_CPU);





	SAFE_RELEASE(m_sys_min_step);
	SAFE_RELEASE(m_sys_max_step);

	if (m_env.pInput)
	{
		m_env.pInput->ShutDown();
		m_env.pInput = NULL;
	}

	SAFE_DELETE(m_pStreamEngine);

	SAFE_RELEASE(m_pNotificationNetwork);
#if !defined(CAFE) && defined(USE_TELEMETRY)
	SAFE_RELEASE(m_env.pTelemetrySystem);
	SAFE_RELEASE(m_pTelemetryFileStream);
	SAFE_RELEASE(m_pTelemetryUDPStream);
#endif
	SAFE_RELEASE(m_env.pConsole);
	SAFE_RELEASE(m_env.pScriptSystem);

	SAFE_DELETE(m_env.pSoftCodeMgr);
	SAFE_DELETE(m_pMemStats);
	SAFE_DELETE(m_pSizer);
	SAFE_DELETE(m_env.pCryPak);
	m_pValidator = NULL;
	SAFE_DELETE(m_pDefaultValidator);

	SAFE_DELETE(m_pPhysRenderer);

#ifdef DOWNLOAD_MANAGER
	SAFE_RELEASE(m_pDownloadManager);
#endif //DOWNLOAD_MANAGER

	SAFE_DELETE(m_pLocalizationManager);

	//DebugStats(false, false);//true);
	//CryLogAlways("");
	//CryLogAlways("release mode memory manager stats:");
	//DumpMMStats(true);
	
	SAFE_DELETE(m_pCpu);

	delete m_pCmdLine;
	m_pCmdLine = 0;







	// TODO: cleanup -RL
	//m_env.bSystemShutDown = true;

	// Log must be last thing released.
	SAFE_RELEASE(m_env.pProfileLogSystem);
	m_env.pLog->FlushAndClose();
	SAFE_RELEASE(m_env.pLog);		// creates log backup

#if defined(MAP_LOADING_SLICING)
	delete gEnv->pSystemScheduler;
#endif // defined(MAP_LOADING_SLICING)
}

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
void CSystem::Quit()
{
	m_bQuit=true;

	if (m_pUserCallback)
		m_pUserCallback->OnQuit();









	if (gEnv->pCryPak && gEnv->pCryPak->GetLvlResStatus())
			LvlRes_export(0);			// executable was started with -LvlRes so it should export lvlres file on quit
	// Fast Quit.


	if( gEnv->pSoundSystem )
	{
		// disallow readrequest during unload to speed up level unloading
		gEnv->pSoundSystem->SetAllowReadRequests(false);
	}

	// flush streaming system
	if(m_pStreamEngine)
		m_pStreamEngine->Shutdown();

	// shut down Audio to safely close down XAudio instances
	if(m_env.pMusicSystem)
	{
		m_env.pMusicSystem->Release();
		m_env.pMusicSystem = m_pNULLSoundSystem->CreateMusicSystem();
	}

	if(m_env.pSoundSystem)
	{
		m_env.pSoundSystem->Silence(true, true); 
		m_env.pSoundSystem->GetInterfaceExtended()->DeactivateAudioDevice();
		m_env.pSoundSystem = m_pNULLSoundSystem;
	}
	
	if( gEnv->pSoundSystem )
	{
		gEnv->pSoundSystem->SetAllowReadRequests(true);
	}

  if(GetIRenderer())
    GetIRenderer()->RestoreGamma();

	if ((m_pCVarQuit && m_pCVarQuit->GetIVal() != 0) || m_bTestMode)
	{
		//Ensure that the load ticker is not currently running. It can perform tasks on the network systems while they're being shut down
		if( m_env.pGame && m_env.pGame->GetIGameFramework() )
		{
			m_env.pGame->GetIGameFramework()->StopNetworkStallTicker();
		}

		if (m_env.pNetwork)
			m_env.pNetwork->FastShutdown();

		// Dispatch quit event so other systems can do any last minute processing
		if (m_pSystemEventDispatcher)
			m_pSystemEventDispatcher->OnSystemEvent(ESYSTEM_EVENT_SHUTDOWN, 0, 0);

#if !defined(PS3) && !defined(XENON)
		// HACK! to save cvars on quit.
		SaveConfiguration();
#endif
		if(m_env.pGame)
			m_env.pGame->Shutdown();

		if(GetIRenderer())
		{
			GetIRenderer()->StopRenderIntroMovies(false);
			GetIRenderer()->StopLoadtimeFlashPlayback();
			GetIRenderer()->ShutDownFast();
		}

		CryLogAlways( "System:Quit" );
		// Commit files changes to the disk.
		_flushall();

		//////////////////////////////////////////////////////////////////////////
		// Support relaunching for windows media center edition.
		//////////////////////////////////////////////////////////////////////////
#if defined(WIN32) && !defined(XENON)
		if (m_pCmdLine && strstr(m_pCmdLine->GetCommandLine(),"ReLaunchMediaCenter") != 0)
		{
			ReLaunchMediaCenter();
		}
#endif

#if CAPTURE_REPLAY_LOG
		CryGetIMemReplay()->Stop();
#endif
		
		//////////////////////////////////////////////////////////////////////////
		// [marco] in test mode, kill the process and quit without performing full C libs cleanup
		// (for faster closing of application)
		CRY_ASSERT(m_pCVarQuit->GetIVal());




		_exit(0);

	}
#if !defined(XENON) && !defined(PS3) && !defined(LINUX) && !defined(gringo)
	PostQuitMessage(0);
#endif
}
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
bool CSystem::IsQuitting()
{
	return (m_bQuit);
}
 
//////////////////////////////////////////////////////////////////////////
void CSystem::SetIProcess(IProcess *process)
{
	m_pProcess = process; 
	//if (m_pProcess)
		//m_pProcess->SetPMessage("");
}

//////////////////////////////////////////////////////////////////////////
// Physics thread task
//////////////////////////////////////////////////////////////////////////
class CPhysicsThreadTask : public IThreadTask
{
public:

	CPhysicsThreadTask()
	{
		m_bStopRequested=0; m_bIsActive=0; m_stepRequested=0; m_bProcessing=0; m_doZeroStep=0;
		m_bSyncStep=false; m_bStepping=false; m_lastStepTimeTaken=0U; m_lastWaitTimeTaken = 0U; 




#if EMBED_PHYSICS_AS_FIBER
		m_PhysFiber=NULL; m_bSyncStep=false;
#endif
	}

#if EMBED_PHYSICS_AS_FIBER
	void SetFiber(JobManager::Fiber::FiberTask* pPhysFiber ) { m_PhysFiber = pPhysFiber; }
#endif
	//////////////////////////////////////////////////////////////////////////
	// IThreadTask implementation.
	//////////////////////////////////////////////////////////////////////////
	virtual void OnUpdate()
	{
		Run();
		// At the end.. delete the task
		delete this;
	}
	virtual void Stop()
	{
		Cancel();
	}
	virtual SThreadTaskInfo* GetTaskInfo() { return &m_TaskInfo; }
	//////////////////////////////////////////////////////////////////////////






























	void StartPix() {}
	void StopPix() {}
	void RequestPixCapture() {}


	virtual void Run()
	{
		m_bStopRequested = 0;
		m_bIsActive = 1;

		float step,timeTaken,kSlowdown=1.0f;
		int nSlowFrames=0;
		tick_t timeStart;
#ifdef ENABLE_LW_PROFILERS
    LARGE_INTEGER stepStart, stepEnd;
#endif
		LARGE_INTEGER waitStart, waitEnd;
		uint64 yieldBegin=0U;
		MarkThisThreadForDebugging("Physics");

		while(true)
		{
		
			QueryPerformanceCounter(&waitStart);
			m_FrameEvent.Wait(); // Wait untill new frame
			QueryPerformanceCounter(&waitEnd);
			m_lastWaitTimeTaken=waitEnd.QuadPart-waitStart.QuadPart;

			if (m_bStopRequested)
			{
				UnmarkThisThreadFromDebugging();
				return;
			}	
			bool stepped = false; 
			m_bStepping = true; 
#ifdef ENABLE_LW_PROFILERS
      QueryPerformanceCounter(&stepStart);
#endif
			while ((step=m_stepRequested)>0 || m_doZeroStep)
			{
				stepped = true; 
				m_stepRequested=0; m_bProcessing=1; m_doZeroStep=0;
				//============
				StartPix();
				//============
				PhysicsVars *pVars = gEnv->pPhysicalWorld->GetPhysVars();
				pVars->bMultithreaded = 1;
				gEnv->pPhysicalWorld->TracePendingRays(); 
				if (kSlowdown!=1.0f) 
				{
					step = max(1,FtoI(step*kSlowdown*50-0.5f))*0.02f;
					pVars->timeScalePlayers = 1.0f/max(kSlowdown,0.2f);
				}	else
					pVars->timeScalePlayers = 1.0f;
				step = min(step, pVars->maxWorldStep);
				timeStart = gEnv->pTimer->GetNonFiberTicks();
				gEnv->pPhysicalWorld->TimeStep(step);
				timeTaken = gEnv->pTimer->TicksToSeconds(gEnv->pTimer->GetNonFiberTicks() - timeStart);
				if (timeTaken>step*0.9f)
				{
					if (++nSlowFrames>5)
						kSlowdown = step*0.9f/timeTaken;
				} else 
					kSlowdown=1.0f, nSlowFrames=0;
				gEnv->pPhysicalWorld->TracePendingRays(2); 
				m_bProcessing=0; 
				//int timeSleep = (int)((m_timeTarget-gEnv->pTimer->GetAsyncTime()).GetMilliSeconds()*0.9f);
				//Sleep(max(0,timeSleep));
				//==========
				StopPix();
				//==========
			}
			m_bStepping=false; if (!stepped) YIELD_PHYSFIBER(); 
#ifdef ENABLE_LW_PROFILERS
      QueryPerformanceCounter(&stepEnd);
      m_lastStepTimeTaken=stepEnd.QuadPart-stepStart.QuadPart;
#endif
		}
	}
	virtual void Cancel()
	{
		Pause();
		m_bStopRequested = 1;
		m_FrameEvent.Set();
		m_bIsActive = 0;
	}

	int Pause()
	{
		if (m_bIsActive) 
		{
			gEnv->pPhysicalWorld->GetPhysVars()->lastTimeStep = 0;
			m_bIsActive = 0;
			while(m_bProcessing) 
				SWITCH_TO_PHYSFIBER(m_PhysFiber);
			return 1;
		}
		gEnv->pPhysicalWorld->GetPhysVars()->lastTimeStep = 0;
		return 0;
	}
	int Resume()
	{
		if (!m_bIsActive)
		{
			m_bIsActive = 1;
			return 1;
		}
		return 0;
	}
	int IsActive() { return m_bIsActive; }
	int RequestStep(float dt)
	{
		if (m_bIsActive)
		{
			if (m_bSyncStep) SyncStep(); 
			m_stepRequested += dt; 
			if (dt<=0.0f)
				m_doZeroStep = 1;
			m_FrameEvent.Set();
		}

		return m_bProcessing; 
	}
	float GetRequestedStep() { return m_stepRequested; }

	void EnableYield(bool enable) 
	{ 
#if EMBED_PHYSICS_AS_FIBER
		if (m_PhysFiber) 
		{ 
			if (enable == false) 
				m_PhysFiber->m_Flags |= JobManager::Fiber::FIBERTASK_SUSPENDED; 
			else
				m_PhysFiber->m_Flags &= ~JobManager::Fiber::FIBERTASK_SUSPENDED; 
		} 
#endif 
	} 

	void SyncStep() 
	{ 
#if EMBED_PHYSICS_AS_FIBER
		if (m_PhysFiber) 
		{ 
			while (m_bStepping) 
				SWITCH_TO_PHYSFIBER(m_PhysFiber);
		} 
#endif 
	} 

	uint64 LastStepTaken() const
	{
		return m_lastStepTimeTaken; 
	} 

	uint64 LastWaitTime() const
	{
		return m_lastWaitTimeTaken; 
	} 

protected:

	volatile int m_bStopRequested;
	volatile int m_bIsActive; 
	volatile float m_stepRequested;
	volatile int m_bProcessing;
	volatile int m_doZeroStep;
	volatile bool m_bSyncStep; 
	volatile bool m_bStepping;
	volatile uint64 m_lastStepTimeTaken;
	volatile uint64 m_lastWaitTimeTaken;

#if !EMBED_PHYSICS_AS_FIBER
	CryEvent m_FrameEvent;
#else
	struct FiberEvent{ 
		int m_EventFlag; 
		FiberEvent() : m_EventFlag() {}
		void Set() { m_EventFlag = 1; JobManager::Fiber::SwitchFiberDirect(); }
		void Wait() { while (m_EventFlag!=1) JobManager::Fiber::SwitchFiberDirect(); m_EventFlag=0; }
	}; 
	FiberEvent m_FrameEvent;
#endif  

	SThreadTaskInfo m_TaskInfo;







#if EMBED_PHYSICS_AS_FIBER
	JobManager::Fiber::FiberTask* m_PhysFiber; 
#endif
};

void CSystem::CreatePhysicsThread()
{
	if (!m_PhysThread)/* && (unsigned int)m_sys_physics_CPU->GetIVal()<m_pCpu->GetPhysCPUCount()
#if defined (XENON)
*2
#endif
		)*/
	{
		//////////////////////////////////////////////////////////////////////////
		SThreadTaskParams threadParams;
		threadParams.name = "Physics";
		threadParams.nFlags = THREAD_TASK_BLOCKING;
		threadParams.nStackSizeKB = PHYSICS_STACK_SIZE>>10;






		{
			ScopedSwitchToGlobalHeap globalHeap;
			m_PhysThread = new CPhysicsThreadTask;
			GetIThreadTaskManager()->RegisterTask( m_PhysThread,threadParams );

			/*
			m_PhysThread.Start(m_pCpu->GetPhysCPUAffinityMask(m_sys_physics_CPU->GetIVal()));
			//Timur, temporary hack for GDC 2008
			#ifdef XENON
			XSetThreadProcessor(m_PhysThread.GetHandle(),2); // Run on core 2 hw thread 0
			#endif
			*/
		}
	}

	if (g_cvars.sys_limit_phys_thread_count) 
	{
		PhysicsVars *pVars = gEnv->pPhysicalWorld->GetPhysVars();
		pVars->numThreads = max(1, min(pVars->numThreads, (int)m_pCpu->GetPhysCPUCount()-1));
	}
}

void CSystem::KillPhysicsThread()
{
	if (m_PhysThread)
	{
		GetIThreadTaskManager()->UnregisterTask( m_PhysThread );
		m_PhysThread = 0;
	}
}

#if EMBED_PHYSICS_AS_FIBER
namespace 
{ 
	static void RunPhysicsFiber(void* pArgument)
	{
		CPhysicsThreadTask* pPhysTask = reinterpret_cast<CPhysicsThreadTask*>(pArgument);
		pPhysTask->OnUpdate(); 
	}
} 

void CSystem::CreatePhysicsFiber() 
{ 
	if (m_PhysFiber == NULL) 
	{ 
		m_PhysThread = new CPhysicsThreadTask;
		m_PhysFiber = JobManager::Fiber::CreateFiber(RunPhysicsFiber, m_PhysThread, PHYSICS_STACK_SIZE); 
		static_cast<CPhysicsThreadTask*>(m_PhysThread)->SetFiber(m_PhysFiber);
	} 
} 
void CSystem::KillPhysicsFiber() 
{ 
	if (m_PhysFiber != NULL) 
	{ 
		JobManager::Fiber::JoinFiber(m_PhysFiber); 
		JobManager::Fiber::DestroyFiber(m_PhysFiber); 
		delete m_PhysThread;
		m_PhysThread = NULL;
		m_PhysFiber = NULL; 
	} 
} 
#endif 

#if !defined(CAFE) && defined(USE_TELEMETRY)
//////////////////////////////////////////////////////////////////////////
void CSystem::TelemetryStreamFileChanged(ICVar *pCVar)
{
	CRY_ASSERT(pCVar);

	if(CSystem *pThis = static_cast<CSystem *>(gEnv->pSystem))
	{
		if(Telemetry::CTelemetrySystem *pTelemetrySystem = static_cast<Telemetry::CTelemetrySystem *>(pThis->m_env.pTelemetrySystem))
		{
			if(Telemetry::CFileStream *pTelemetryFileStream = pThis->m_pTelemetryFileStream)
			{
				pTelemetrySystem->Flush();

				pTelemetrySystem->DetachStream(pTelemetryFileStream);

				pTelemetryFileStream->Shutdown();

				const char	*pFileName = pCVar->GetString();

				if((pFileName[0] != '0') && (pFileName[0] != '\0'))
				{
					if(pTelemetryFileStream->Init(pFileName))
					{
						pTelemetrySystem->AttachStream(pTelemetryFileStream);
					}
					else
					{
						CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Failed to initialize telemetry file stream!");
					}
				}
			}
		}
	}
}

//////////////////////////////////////////////////////////////////////////
void CSystem::TelemetryStreamIPChanged(ICVar* pCVar)
{
	CRY_ASSERT(pCVar);

	if(CSystem *pThis = static_cast<CSystem *>(gEnv->pSystem))
	{
		if(Telemetry::CTelemetrySystem *pTelemetrySystem = static_cast<Telemetry::CTelemetrySystem *>(pThis->m_env.pTelemetrySystem))
		{
			if(Telemetry::CUDPStream *pTelemetryUDPStream = pThis->m_pTelemetryUDPStream)
			{
				pTelemetrySystem->Flush();

				pTelemetrySystem->DetachStream(pTelemetryUDPStream);

				pTelemetryUDPStream->Shutdown();

				const char	*pIPAddress = pCVar->GetString();

				if((pIPAddress[0] != '0') && (pIPAddress[0] != '\0'))
				{
					if(pTelemetryUDPStream->Init(pIPAddress))
					{
						pTelemetrySystem->AttachStream(pTelemetryUDPStream);
					}
					else
					{
						CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Failed to initialize telemetry UDP stream!");
					}
				}
			}
		}
	}
}
#endif

//////////////////////////////////////////////////////////////////////////
int CSystem::SetThreadState(ESubsystem subsys, bool bActive)
{
	switch (subsys)
	{
	case ESubsys_Physics: 
		{
			if (m_PhysThread)
			{
				return bActive ? ((CPhysicsThreadTask*)m_PhysThread)->Resume() : ((CPhysicsThreadTask*)m_PhysThread)->Pause();
			}

		}
		break;
	}
	return 0;
}

//////////////////////////////////////////////////////////////////////////
void CSystem::SleepIfInactive()
{
	// ProcessSleep()
	if (m_bDedicatedServer || m_bEditor || gEnv->bMultiplayer || sys_SleepIfInactive==0)
		return;
	
	if (m_bBrowserMode)
	{
		Sleep(1);
		return;
	}
	
#if defined(WIN32) && !defined(XENON)
	WIN_HWND hRendWnd = GetIRenderer()->GetHWND();
	if (!hRendWnd)
		return;

	// Loop here waiting for window to be activated.
	for (int nLoops = 0; nLoops < 5; nLoops++)
	{
		WIN_HWND hActiveWnd = m_bBrowserMode ? ::GetForegroundWindow() : ::GetActiveWindow();
		if (hActiveWnd == hRendWnd)
		{
			if (m_bBrowserMode)
				Sleep(1);
			break;
		}

		if (m_hWnd)
		{
			// Peek message.
			MSG msg;
			// Must be PeekMessageW for Scaleform IME to function correctly and to ensure WM_CHAR contains
			// Unicode widechar for languages like Russian
			while (PeekMessageW(&msg, (HWND)m_hWnd, 0, 0, PM_REMOVE))
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
		if (gEnv->pGame && gEnv->pGame->GetIGameFramework())
		{
			// During the time demo, do not sleep even in inactive window.
			if (gEnv->pGame->GetIGameFramework()->IsInTimeDemo())
				break;
		}
		Sleep(5);
	}
#endif      
}

//////////////////////////////////////////////////////////////////////////
void CSystem::SleepIfNeeded()
{ 
	FUNCTION_PROFILER_FAST( this, PROFILE_SYSTEM, g_bProfilerEnabled );

	ITimer *const pTimer = gEnv->pTimer;
	static bool firstCall = true;

	typedef MiniQueue<CTimeValue, 32> PrevNow;
	static PrevNow prevNow;
	if (firstCall)
	{
		m_lastTickTime = pTimer->GetAsyncTime();
		prevNow.Push(m_lastTickTime);
		firstCall = false;
		return;
	}

	const float maxRate = m_svDedicatedMaxRate->GetFVal();
	const float minTime = 1.0f / maxRate;
	CTimeValue now = pTimer->GetAsyncTime();
	float elapsed = (now - m_lastTickTime).GetSeconds();

	if (prevNow.Full())
		prevNow.Pop();
	prevNow.Push(now);

	static bool allowStallCatchup = true;
	if (elapsed > minTime && allowStallCatchup)
	{
		allowStallCatchup = false;
		m_lastTickTime = pTimer->GetAsyncTime();
		return;
	}
	allowStallCatchup = true;

	float totalElapsed = (now - prevNow.Front()).GetSeconds();
	float wantSleepTime = CLAMP(minTime*(prevNow.Size()-1) - totalElapsed, 0, (minTime - elapsed)*0.9f);
	static float sleepTime = 0;
	sleepTime = (15*sleepTime + wantSleepTime)/16;
	int sleepMS = (int)(1000.0f*sleepTime + 0.5f);
	if (sleepMS > 0)
		Sleep(sleepMS);

	m_lastTickTime = pTimer->GetAsyncTime();
}

//////////////////////////////////////////////////////////////////////
#ifdef WIN32
HWND g_hBreakWnd;
WNDPROC g_prevWndProc;
LRESULT CALLBACK BreakWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	if (msg==WM_HOTKEY)
#ifdef WIN64
		DebugBreak();
#else
		__asm int 3;
#endif
	return CallWindowProc(g_prevWndProc,hWnd,msg,wParam,lParam);
}

HANDLE g_hBreakHotkeyThread = 0;
DWORD WINAPI BreakHotkeyThreadProc(void*)
{
	g_hBreakWnd = CreateWindowEx(0,"Message","",0,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,HWND_MESSAGE,0,GetModuleHandle(0),0);
	g_prevWndProc = (WNDPROC)SetWindowLongPtr(g_hBreakWnd, GWLP_WNDPROC, (LONG_PTR)BreakWndProc);
	RegisterHotKey(g_hBreakWnd,0,0,VK_PAUSE);
	MSG msg;
	while(GetMessage(&msg,g_hBreakWnd,0,0)) 
		DispatchMessage(&msg);
	UnregisterHotKey(g_hBreakWnd,0);
	return 0;
}
#endif

class BreakListener : public IInputEventListener {
	bool OnInputEvent(const SInputEvent &ie) {
		if (ie.deviceId==eDI_Keyboard && ie.keyId==eKI_Pause && ie.state & (eIS_Pressed|eIS_Down))
			CryDebugBreak();
		return true;
	}
} g_BreakListener;

volatile int g_lockInput = 0;

struct SBreakListenerTask : public IThreadTask 
{
	SBreakListenerTask() { m_bStop=0; m_nBreakIdle=0; }
	virtual void OnUpdate() {
		do {
			Sleep(200);
			if (++m_nBreakIdle>1)
			{ WriteLock lock(g_lockInput);
				gEnv->pInput->Update(true);
				m_nBreakIdle = 0;
			}
		} while(!m_bStop);
	}
	virtual void Stop() { m_bStop=1; }
	virtual SThreadTaskInfo* GetTaskInfo() { return &m_TaskInfo; }
	volatile int m_bStop;
	int m_nBreakIdle;
	SThreadTaskInfo m_TaskInfo;
};
SBreakListenerTask g_BreakListenerTask;
bool g_breakListenerOn = false;

extern DWORD g_idDebugThreads[];
extern int g_nDebugThreads;
int prev_sys_float_exceptions = -1;

//////////////////////////////////////////////////////////////////////
bool CSystem::Update( int updateFlags, int nPauseMode )
{
#ifndef EXCLUDE_UPDATE_ON_CONSOLE
	// do the dedicated sleep earlier than the frame profiler to avoid having it counted
	if (gEnv->IsDedicated())
	{
#if defined(MAP_LOADING_SLICING)
		gEnv->pSystemScheduler->SchedulingSleepIfNeeded();
#else
		SleepIfNeeded();
#endif // defined(MAP_LOADING_SLICING)
	}
#endif //EXCLUDE_UPDATE_ON_CONSOLE
#if CAPTURE_REPLAY_LOG
  if(CryGetIMemoryManager() && CryGetIMemReplay())
	{
	  CryGetIMemReplay()->AddFrameStart();
		if ((-- m_ttMemStatSS) <= 0)
		{
			CryGetIMemReplay()->AddScreenshot();
			m_ttMemStatSS = 30;
		}
	}
#endif //CAPTURE_REPLAY_LOG

	SWITCH_TO_PHYSFIBER(m_PhysFiber); 
	m_pPlatformOS->Tick(m_Time.GetRealFrameTime());

#ifndef EXCLUDE_UPDATE_ON_CONSOLE
	if (g_cvars.sys_keyboard_break && !g_breakListenerOn)
	{
#ifdef WIN32
		if (m_bEditor)
			g_hBreakHotkeyThread = CreateThread(0,1024,BreakHotkeyThreadProc,0,0,0);
#endif //WIN32
		SThreadTaskParams ttp;
		ttp.name = "BreakListenerThread";
		ttp.nFlags = THREAD_TASK_BLOCKING;
		g_BreakListenerTask.m_bStop = 0;
		GetIThreadTaskManager()->RegisterTask( &g_BreakListenerTask, ttp );
		gEnv->pInput->AddEventListener(&g_BreakListener);
		g_breakListenerOn = true;
	} else if (!g_cvars.sys_keyboard_break && g_breakListenerOn) 
	{
#ifdef WIN32
		if (g_hBreakHotkeyThread)
			TerminateThread(g_hBreakHotkeyThread,0);
#endif //WIN32
		gEnv->pInput->RemoveEventListener(&g_BreakListener);
		GetIThreadTaskManager()->UnregisterTask(&g_BreakListenerTask);
		g_breakListenerOn = false;
	}
#endif //EXCLUDE_UPDATE_ON_CONSOLE
#ifdef WIN32
	// enable/disable SSE fp exceptions (#nan and /0)
	// need to do it each frame since sometimes they are being reset
	_mm_setcsr(_mm_getcsr() & ~0x280 | (g_cvars.sys_float_exceptions>0 ? 0 : 0x280));
#endif //WIN32

	FUNCTION_PROFILER_FAST( GetISystem(),PROFILE_SYSTEM,g_bProfilerEnabled );

	m_nUpdateCounter++;
#ifndef EXCLUDE_UPDATE_ON_CONSOLE
	if(!m_sDelayedScreeenshot.empty())
	{
		gEnv->pRenderer->ScreenShot(m_sDelayedScreeenshot.c_str());
		m_sDelayedScreeenshot.clear();
	}

	// Check if game needs to be sleeping when not active.
	SleepIfInactive();

	if (m_pUserCallback)
		m_pUserCallback->OnUpdate();

	//////////////////////////////////////////////////////////////////////////
	// Enable/Disable floating exceptions.
	//////////////////////////////////////////////////////////////////////////
	prev_sys_float_exceptions += 1+g_cvars.sys_float_exceptions & prev_sys_float_exceptions>>31;
	if (prev_sys_float_exceptions != g_cvars.sys_float_exceptions)
	{
		prev_sys_float_exceptions = g_cvars.sys_float_exceptions;

		EnableFloatExceptions( g_cvars.sys_float_exceptions );
		UpdateFPExceptionsMaskForThreads();
	}
#endif //EXCLUDE_UPDATE_ON_CONSOLE
	//////////////////////////////////////////////////////////////////////////

	CTimeValue updateStart = gEnv->pTimer->GetAsyncTime();
	SWITCH_TO_PHYSFIBER(m_PhysFiber);

	if (m_env.pLog)
		m_env.pLog->Update();

#if !defined(RELEASE) || defined(RELEASE_LOGGING) || defined(ENABLE_PROFILING_CODE)
	GetIRemoteConsole()->Update();
#endif

//	if (updateFlags&ESYSUPDATE_EDITOR && gEnv->pLocalMemoryUsage != NULL)
	{
		//gEnv->pLocalMemoryUsage->OnUpdate();
	}

	if(!gEnv->IsEditor() && gEnv->pRenderer)
	{
		// if aspect ratio changes or is different from default we need to update camera
		float fCurrentProjRatio = GetViewCamera().GetProjRatio();
		float fNewProjRatio = fCurrentProjRatio;
		
		float fPAR = gEnv->pRenderer->GetPixelAspectRatio();

		uint32 dwWidth = m_rWidth->GetIVal();
		uint32 dwHeight = m_rHeight->GetIVal();
		
		float fHeight = ((float)dwHeight)*fPAR;
		
		if(fHeight > 0.0f)
			fNewProjRatio = (float)dwWidth / fHeight;

		GetViewCamera().SetFrustum(m_rWidth->GetIVal(),m_rHeight->GetIVal(),GetViewCamera().GetFov(),GetViewCamera().GetNearPlane(),GetViewCamera().GetFarPlane(), fPAR);
	}
#ifndef EXCLUDE_UPDATE_ON_CONSOLE
	if(m_pTestSystem)
		m_pTestSystem->Update();
#endif //EXCLUDE_UPDATE_ON_CONSOLE
	if (nPauseMode != 0)
		m_bPaused = true;
	else
		m_bPaused = false;

	if (m_env.pGame)
	{
		//bool bDevMode = m_env.pGame->GetModuleState( EGameDevMode );
		//if (bDevMode != m_bInDevMode)
			//SetDevMode(bDevMode);
	}
#ifdef PROFILE_WITH_VTUNE
	if (m_bInDevMode)
	{	
		if (VTPause != NULL && VTResume != NULL)
		{
			static bool bVtunePaused = true;
			
			bool bPaused = false;
			
			if (GetISystem()->GetIInput())
			{
				bPaused = !(GetKeyState(VK_SCROLL) & 1);
			}

			{
				if (bVtunePaused && !bPaused)
				{
					GetIProfilingSystem()->VTuneResume();
				}
				if (!bVtunePaused && bPaused)
				{
					GetIProfilingSystem()->VTunePause();
				}
				bVtunePaused = bPaused;
			}
		}
	}
#endif //PROFILE_WITH_VTUNE

#ifdef SOFTCODE_SYSTEM_ENABLED
	if (m_env.pSoftCodeMgr)
		m_env.pSoftCodeMgr->PollForNewModules();
#endif

	if (m_pStreamEngine)
	{
		FRAME_PROFILER( "StreamEngine::Update()", this, PROFILE_SYSTEM );
		m_pStreamEngine->Update();
	}
#ifndef EXCLUDE_UPDATE_ON_CONSOLE
	if (m_bIgnoreUpdates)
		return true;
#endif //EXCLUDE_UPDATE_ON_CONSOLE
	if (m_env.pCharacterManager)
		m_env.pCharacterManager->Update(nPauseMode != 0);

  //static bool sbPause = false; 
	//bool bPause = false;
	bool bNoUpdate = false;
#ifndef EXCLUDE_UPDATE_ON_CONSOLE
	//check what is the current process 
	IProcess *pProcess=GetIProcess();
	if (!pProcess)
		return (true); //should never happen

	if (m_sysNoUpdate && m_sysNoUpdate->GetIVal())
	{
		bNoUpdate = true;
		updateFlags = ESYSUPDATE_IGNORE_AI | ESYSUPDATE_IGNORE_PHYSICS;
	}

	//if ((pProcess->GetFlags() & PROC_MENU) || (m_sysNoUpdate && m_sysNoUpdate->GetIVal()))
	//		bPause = true;
	m_bNoUpdate = bNoUpdate;		
#endif //EXCLUDE_UPDATE_ON_CONSOLE
	//check if we are quitting from the game
	if (IsQuitting())
		return (false);
	

#ifndef XENON
#ifdef WIN32
  // process window messages
	{
		FRAME_PROFILER( "SysUpdate:PeekMessageW",this,PROFILE_SYSTEM );

		if (m_hWnd && ::IsWindow((HWND)m_hWnd))
		{
			MSG msg;
			// Must be PeekMessageW for Scaleform IME to function correctly and to ensure WM_CHAR contains
			// Unicode widechar for languages like Russian
			while (PeekMessageW(&msg, (HWND)m_hWnd, 0, 0, PM_REMOVE))       
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
  }
#endif //_XBOX
#endif //WIN32

	//limit frame rate for PC here
	//for consoles this is done inside renderthread to be vsync dependent
#if !defined(PS3) && !defined(XENON) && !defined(CAFE)
	if(g_cvars.sys_MaxFPS)
	{		
		gEnv->GetJobManager()->AddStartMarker("CapFrameRate", eTI_CapFrameRate);
		CTimeValue timeFrameMax;		
		timeFrameMax.SetMilliSeconds((int64)(1000.f/(float)g_cvars.sys_MaxFPS));
		static CTimeValue sTimeLast = gEnv->pTimer->GetAsyncTime();
		const CTimeValue timeLast = timeFrameMax + sTimeLast;
		while(timeLast.GetValue() > gEnv->pTimer->GetAsyncTime().GetValue())
		{
			volatile int i=0;
			while(i++ < 1000);
		}
		sTimeLast = gEnv->pTimer->GetAsyncTime();
		gEnv->GetJobManager()->AddStopMarker(eTI_CapFrameRate);
	}
#endif
	//////////////////////////////////////////////////////////////////////
	//update time subsystem	
	m_Time.UpdateOnFrameStart();

	if (m_env.p3DEngine)
		m_env.p3DEngine->OnFrameStart();

	//////////////////////////////////////////////////////////////////////
	// update rate limiter for dedicated server
	if (m_pServerThrottle.get())
		m_pServerThrottle->Update();

	static ICVar *pFixedTimeStep = gEnv->pConsole->GetCVar("t_FixedStep");
	float fMovieFrameTime;

	// The reason that we use this equation instead of the simpler 'GetFrameTime()'
	// is that we want the movie system affected only by the fixed time step & time scale settings.
	// (For instance, not affected by the game pause, etc.)
	if (pFixedTimeStep->GetFVal() == 0)
	{
		fMovieFrameTime = m_Time.GetRealFrameTime() * m_Time.GetTimeScale();
	}
	else
	{
		fMovieFrameTime = pFixedTimeStep->GetFVal();
	}

	//////////////////////////////////////////////////////////////////////
	// initial network update
	if (m_env.pNetwork)
	{
		m_env.pNetwork->SyncWithGame(eNGS_FrameStart);
	}

#if !defined(CAFE) && defined(USE_TELEMETRY)
	//////////////////////////////////////////////////////////////////////////
	// Update telemetry system.
	m_env.pTelemetrySystem->Update();
#endif

	//////////////////////////////////////////////////////////////////////////
	// Update script system.
	if (m_env.pScriptSystem)
	{
		FRAME_PROFILER( "SysUpdate:ScriptSystem",this,PROFILE_SYSTEM );
		gEnv->GetJobManager()->AddStartMarker("ScriptSystem",eTI_ScriptSys);
		SNTunerAutoMarker::StartMarker(eTI_ScriptSys, "ScriptSystem");
		m_env.pScriptSystem->Update();
		SNTunerAutoMarker::StopMarker(eTI_ScriptSys);
		gEnv->GetJobManager()->AddStopMarker(eTI_ScriptSys);
	}
	
	if (m_env.pInput)
	{
		bool updateInput =
			!(updateFlags&ESYSUPDATE_EDITOR) ||
			(updateFlags&ESYSUPDATE_EDITOR_AI_PHYSICS);
		if (updateInput)
		{
			//////////////////////////////////////////////////////////////////////
			//update input system
#ifndef WIN32
			m_env.pInput->Update(true);
#else
      bool bFocus = (::GetForegroundWindow()==m_hWnd) || m_bEditor;
			{ WriteLock lock(g_lockInput);
				m_env.pInput->Update(bFocus);
				g_BreakListenerTask.m_nBreakIdle = 0;
			}
#endif //WIN32
		}
	}
	SWITCH_TO_PHYSFIBER(m_PhysFiber);

	//////////////////////////////////////////////////////////////////////
	//update console system
	if (m_env.pConsole)
	{
		FRAME_PROFILER( "SysUpdate:Console",this,PROFILE_SYSTEM );

		if (!(updateFlags&ESYSUPDATE_EDITOR))
			m_env.pConsole->Update();
	}
#ifndef EXCLUDE_UPDATE_ON_CONSOLE
	//////////////////////////////////////////////////////////////////////
	//update notification network system
	if (m_pNotificationNetwork)
	{
		m_pNotificationNetwork->Update();
	}
#endif //EXCLUDE_UPDATE_ON_CONSOLE
	//////////////////////////////////////////////////////////////////////
	//update sound system Part 1 if in Editor / in Game Mode Viewsystem updates the Listeners
	if (!m_env.IsEditorGameMode())
	{
		if (updateFlags & ESYSUPDATE_EDITOR && !bNoUpdate)
		{
			// updating the Listener Position in a first separate step
			if ((nPauseMode!=1))
			{
				if (m_env.pGame)
				{
					IGameFramework* pIGameFramework = m_env.pGame->GetIGameFramework();
					if (pIGameFramework)
					{
						if (pIGameFramework->GetIViewSystem())
						{
						IView* const pActiveView = pIGameFramework->GetIViewSystem()->GetActiveView();
						if (pActiveView)
						{
							ListenerID const nListenerID = pActiveView->GetSoundListenerID();
							if (nListenerID != LISTENERID_INVALID)
							{
									IListener* pListener = m_env.pSoundSystem->GetListener(nListenerID);
									Matrix34 listenerMatrix = m_ViewCamera.GetMatrix();

									//if the entityID is not set, we should use the listener matrix
									if(pListener && (pListener->GetEntityID() == 0))
										listenerMatrix = pListener->GetMatrix();

									m_env.pSoundSystem->SetListener(nListenerID, listenerMatrix, Vec3(0,0,0), true, 1.0);
								m_env.pSoundSystem->Update(eSoundUpdateMode_Listeners);
							}
						}
					}				
				}
			}
		}
	}
	}

	//////////////////////////////////////////////////////////////////////	
	// update entity system (a little bit) before physics
	if(nPauseMode!=1)
	{
			//////////////////////////////////////////////////////////////////////
			//update entity system	
			if (m_env.pEntitySystem && !bNoUpdate && g_cvars.sys_entitysystem)
			{
			gEnv->GetJobManager()->AddStartMarker("EntitySystem",eTI_EntitySys);
				SNTunerAutoMarker::StartMarker(eTI_EntitySys, "EntitySystem");
				m_env.pEntitySystem->PrePhysicsUpdate();
				SNTunerAutoMarker::StopMarker(eTI_EntitySys);
			gEnv->GetJobManager()->AddStopMarker(eTI_EntitySys);
			}
		}

	//////////////////////////////////////////////////////////////////////////
	// Update Threads Task Manager.
	//////////////////////////////////////////////////////////////////////////
	m_pThreadTaskManager->OnUpdate();

	//////////////////////////////////////////////////////////////////////////
	// Update Resource Manager.
	//////////////////////////////////////////////////////////////////////////
	m_pResourceManager->Update();

	//////////////////////////////////////////////////////////////////////	
	// update physic system	
	//static float time_zero = 0;
	if(!m_bUIFrameworkMode)
	{
#if !EMBED_PHYSICS_AS_FIBER
	if (m_sys_physics_CPU->GetIVal()>0 && !gEnv->IsDedicated())
		CreatePhysicsThread();
	else
		KillPhysicsThread();
#else
	if (m_sys_physics_CPU->GetIVal()>0 && !gEnv->IsDedicated())
		CreatePhysicsFiber(); 
	else
		KillPhysicsFiber();
#endif 

	static int g_iPausedPhys = 0;
	PhysicsVars *pVars = m_env.pPhysicalWorld->GetPhysVars();
	pVars->threadLag = 0;

	CPhysicsThreadTask* pPhysicsThreadTask = ((CPhysicsThreadTask*)m_PhysThread);
	if (!pPhysicsThreadTask)
	{
		FRAME_PROFILER( "SysUpdate:AllAIAndPhysics",this,PROFILE_SYSTEM );
		// intermingle physics/AI updates so that if we get a big timestep (frame rate glitch etc) the
		// AI gets to steer entities before they travel over cliffs etc.
		float maxTimeStep = 0.0f;
		if (m_env.pAISystem)
			maxTimeStep = m_env.pAISystem->GetUpdateInterval();
		else
			maxTimeStep = 0.25f;
		int maxSteps = 1;
		float fCurTime = m_Time.GetCurrTime();
		float fPrevTime = m_env.pPhysicalWorld->GetPhysicsTime();
		float timeToDo = m_Time.GetFrameTime();//fCurTime - fPrevTime;
		if (m_env.bMultiplayer)
			timeToDo = m_Time.GetRealFrameTime();
		m_env.pPhysicalWorld->TracePendingRays();
		while (timeToDo > 0.0001f && maxSteps-- > 0)
		{
			float thisStep = min(maxTimeStep, timeToDo);
			timeToDo -= thisStep;

			if ((nPauseMode!=1) && !(updateFlags&ESYSUPDATE_IGNORE_PHYSICS) && g_cvars.sys_physics && !bNoUpdate)
			{
				FRAME_PROFILER( "SysUpdate:physics",this,PROFILE_SYSTEM );

				int iPrevTime=m_env.pPhysicalWorld->GetiPhysicsTime();
				//float fPrevTime=m_env.pPhysicalWorld->GetPhysicsTime();
				pVars->bMultithreaded = 0;
				pVars->timeScalePlayers = 1.0f;
				if (!(updateFlags&ESYSUPDATE_MULTIPLAYER))
					m_env.pPhysicalWorld->TimeStep(thisStep);
				else
				{
					//@TODO: fixed step in game.
					/*
					if (m_env.pGame->UseFixedStep())
					{
						m_env.pPhysicalWorld->TimeStep(fCurTime-fPrevTime, 0);
						int iCurTime = m_env.pPhysicalWorld->GetiPhysicsTime();

						m_env.pPhysicalWorld->SetiPhysicsTime(m_env.pGame->SnapTime(iPrevTime));
						int i, iStep=m_env.pGame->GetiFixedStep();
						float fFixedStep = m_env.pGame->GetFixedStep();
						for(i=min(20*iStep,m_env.pGame->SnapTime(iCurTime)-m_pGame->SnapTime(iPrevTime)); i>0; i-=iStep)
						{
							m_env.pGame->ExecuteScheduledEvents();
							m_env.pPhysicalWorld->TimeStep(fFixedStep, ent_rigid|ent_skip_flagged);
						}

						m_env.pPhysicalWorld->SetiPhysicsTime(iPrevTime);
						m_env.pPhysicalWorld->TimeStep(fCurTime-fPrevTime, ent_rigid|ent_flagged_only);

						m_env.pPhysicalWorld->SetiPhysicsTime(iPrevTime);
						m_env.pPhysicalWorld->TimeStep(fCurTime-fPrevTime, ent_living|ent_independent|ent_deleted);
					}
					else
					*/
						m_env.pPhysicalWorld->TimeStep(thisStep);

				}
				g_iPausedPhys = 0;
			}	else if (!(g_iPausedPhys++ & 31))
				m_env.pPhysicalWorld->TimeStep(0);	// make sure objects get all notifications; flush deleted ents
      gEnv->pPhysicalWorld->TracePendingRays(2);

			{ FRAME_PROFILER( "SysUpdate:PumpLoggedEvents",this,PROFILE_SYSTEM );
				gEnv->GetJobManager()->AddStartMarker("PumpLoggedEvents",eTI_PumpLoggedEv);
				SNTunerAutoMarker::StartMarker(eTI_PumpLoggedEv, "PumpLoggedEvents");
				m_env.pPhysicalWorld->PumpLoggedEvents();
				SNTunerAutoMarker::StopMarker(eTI_PumpLoggedEv);
				gEnv->GetJobManager()->AddStopMarker(eTI_PumpLoggedEv);
			}

			// now AI
			if ((nPauseMode==0) && !(updateFlags&ESYSUPDATE_IGNORE_AI) && g_cvars.sys_ai && !bNoUpdate)
			{
				FRAME_PROFILER( "SysUpdate:AI",this,PROFILE_SYSTEM );
				//////////////////////////////////////////////////////////////////////
				//update AI system - match physics
				if (m_env.pAISystem && !m_cvAIUpdate->GetIVal() && g_cvars.sys_ai)
					m_env.pAISystem->Update(gEnv->pTimer->GetFrameStartTime(), gEnv->pTimer->GetFrameTime());
			}
		}

		// Make sure we don't lag too far behind
		if ((nPauseMode!=1) && !(updateFlags&ESYSUPDATE_IGNORE_PHYSICS))
		{
			if (fabsf(m_env.pPhysicalWorld->GetPhysicsTime()-fCurTime)>0.01f)
			{
				//GetILog()->LogToConsole("Adjusting physical world clock by %.5f", fCurTime-m_env.pPhysicalWorld->GetPhysicsTime());
				m_env.pPhysicalWorld->SetPhysicsTime(fCurTime);
			}
		}
	}
	else
	{
		{ FRAME_PROFILER( "SysUpdate:PumpLoggedEvents",this,PROFILE_SYSTEM );
			gEnv->GetJobManager()->AddStartMarker("PumpLoggedEvents",eTI_PumpLoggedEv);
			SNTunerAutoMarker::StartMarker(eTI_PumpLoggedEv, "PumpLoggedEvents");
			m_env.pPhysicalWorld->PumpLoggedEvents();
			SNTunerAutoMarker::StopMarker(eTI_PumpLoggedEv);
			gEnv->GetJobManager()->AddStopMarker(eTI_PumpLoggedEv);
		}
		if ((nPauseMode!=1) && !(updateFlags&ESYSUPDATE_IGNORE_PHYSICS))
		{
			pPhysicsThreadTask->Resume();
			float lag = pPhysicsThreadTask->GetRequestedStep();

			if (pPhysicsThreadTask->RequestStep(m_Time.GetFrameTime()))
			{
#if !EMBED_PHYSICS_AS_FIBER
				pVars->threadLag = lag+m_Time.GetFrameTime();
#endif 
				//GetILog()->Log("Physics thread lags behind; accum time %.3f", pVars->threadLag);
			}











		} else
		{
			pPhysicsThreadTask->Pause();
			pPhysicsThreadTask->EnableYield(false);
			m_env.pPhysicalWorld->TracePendingRays();
			m_env.pPhysicalWorld->TracePendingRays(2);
			m_env.pPhysicalWorld->TimeStep(0);
			pPhysicsThreadTask->EnableYield(true);
		}
		if ((nPauseMode==0) && !(updateFlags&ESYSUPDATE_IGNORE_AI) && g_cvars.sys_ai && !bNoUpdate)
		{
			FRAME_PROFILER( "SysUpdate:AI",this,PROFILE_SYSTEM );
			//////////////////////////////////////////////////////////////////////
			//update AI system
			if (m_env.pAISystem && !m_cvAIUpdate->GetIVal())
				m_env.pAISystem->Update(gEnv->pTimer->GetFrameStartTime(), gEnv->pTimer->GetFrameTime());
		}
	}
	SWITCH_TO_PHYSFIBER(m_PhysFiber);
	pe_params_waterman pwm;
	pwm.posViewer = GetViewCamera().GetPosition();
	m_env.pPhysicalWorld->SetWaterManagerParams(&pwm);
	}
	//////////////////////////////////////////////////////////////////////////
	// fix to solve a flaw in the system
	// Update movie system (before entity update is better for having artifact free movie playback)
	//////////////////////////////////////////////////////////////////////////	
	if(g_cvars.sys_earlyMovieUpdate!=0)
	{
		if(!bNoUpdate)
			UpdateMovieSystem(updateFlags,fMovieFrameTime);
	}

#ifndef EXCLUDE_UPDATE_ON_CONSOLE
	if(nPauseMode!=1)
#endif //EXCLUDE_UPDATE_ON_CONSOLE
	{
		//////////////////////////////////////////////////////////////////////
		//update entity system	
		if (m_env.pEntitySystem && !bNoUpdate && g_cvars.sys_entitysystem)
		{
			gEnv->GetJobManager()->AddStartMarker("EntitySystem",eTI_EntitySys);
			SNTunerAutoMarker::StartMarker(eTI_EntitySys, "EntitySystem");
			m_env.pEntitySystem->Update();
			SNTunerAutoMarker::StopMarker(eTI_EntitySys);
			gEnv->GetJobManager()->AddStopMarker(eTI_EntitySys);
		}
	}

	//////////////////////////////////////////////////////////////////////////
	// Update movie system (Must be after updating EntitySystem and AI.
	//////////////////////////////////////////////////////////////////////////	
	// the movie system already disables AI physics etc.
	if(g_cvars.sys_earlyMovieUpdate==0)
	{
		if(!bNoUpdate)
			UpdateMovieSystem(updateFlags,fMovieFrameTime);
	}

	//////////////////////////////////////////////////////////////////////
	//update process (3D engine)
	if (!(updateFlags&ESYSUPDATE_EDITOR) && !bNoUpdate)
	{
		if (ITimeOfDay * pTOD = m_env.p3DEngine->GetTimeOfDay())
			pTOD->Tick();

		if (m_pProcess && (m_pProcess->GetFlags() & PROC_3DENGINE))
		{
			if ((nPauseMode!=1))
			if (!IsEquivalent(m_ViewCamera.GetPosition(),Vec3(0,0,0),VEC_EPSILON))
			{			
				if (m_env.p3DEngine)
				{
//					m_env.p3DEngine->SetCamera(m_ViewCamera);
					m_pProcess->Update();
#ifndef EXCLUDE_UPDATE_ON_CONSOLE
					//////////////////////////////////////////////////////////////////////////
					// Strange, !do not remove... ask Timur for the meaning of this.
					//////////////////////////////////////////////////////////////////////////
					if (m_nStrangeRatio > 32767)
					{
						gEnv->pScriptSystem->SetGCFrequency(-1); // lets get nasty.
					}
					//////////////////////////////////////////////////////////////////////////
					// Strange, !do not remove... ask Timur for the meaning of this.
					//////////////////////////////////////////////////////////////////////////
					if (m_nStrangeRatio > 1000)
					{
						if (m_pProcess && (m_pProcess->GetFlags() & PROC_3DENGINE))
							m_nStrangeRatio += (1 + (10*rand())/RAND_MAX);
					}
#endif //EXCLUDE_UPDATE_ON_CONSOLE
					//////////////////////////////////////////////////////////////////////////
				}
			}
		}
		else
		{
			if (m_pProcess)
				m_pProcess->Update();
		}
	}
	SWITCH_TO_PHYSFIBER(m_PhysFiber);

	//////////////////////////////////////////////////////////////////////
	//update sound system part 2
	if (!g_cvars.sys_deferAudioUpdateOptim && !bNoUpdate)
	{
		UpdateAudioSystems();
	}
	else
	{
		m_bNeedDoWorkDuringOcclusionChecks = true;
	}

	SWITCH_TO_PHYSFIBER(m_PhysFiber);

	//////////////////////////////////////////////////////////////////////
	// final network update
	if (m_env.pNetwork)
	{
		m_env.pNetwork->SyncWithGame(eNGS_FrameEnd);
		m_env.pNetwork->SyncWithGame(eNGS_WakeNetwork);		// This will wake the network thread up
	}

#ifdef DOWNLOAD_MANAGER
	if (m_pDownloadManager && !bNoUpdate)
	{
		m_pDownloadManager->Update();
	}
#endif //DOWNLOAD_MANAGER
#if !defined(PS3) && !defined(LINUX) && !defined(CAFE)
	if (m_sys_SimulateTask->GetIVal() > 0) 
	{
		// have a chance to win longest Pi calculation content
		int64 delay = m_sys_SimulateTask->GetIVal();
		int64 start = CryGetTicks();
		double a = 1.0, b = 1.0/sqrt(2.0), t = 1.0/4.0, p = 1.0, an, bn, tn, pn, Pi = 0.0;
		while (CryGetTicks() - start < delay) {
			// do something
			an = (a + b) / 2.0;
			bn = sqrt(a*b);
			tn = t - p*(a - an)*(a - an);
			pn = 2 * p;

			a = an;
			b = bn;
			t = tn;
			p = pn;

			Pi = (a+b)*(a+b)/4/t;
		}
		//CryLog("Task calculate PI = %f ", Pi); // Thats funny , but it works :-)
	}
#endif //PS3 LINUX
	//Now update frame statistics
	CTimeValue cur_time = gEnv->pTimer->GetAsyncTime();
	
	CTimeValue a_second(g_cvars.sys_update_profile_time);
	std::vector< std::pair<CTimeValue, float> >::iterator it = m_updateTimes.begin();
	for(std::vector< std::pair<CTimeValue, float> >::iterator eit = m_updateTimes.end(); it!=eit; ++it)
		if((cur_time - it->first) < a_second)
			break;
	
	{
		ScopedSwitchToGlobalHeap globalHeap;

		if(it != m_updateTimes.begin())
			m_updateTimes.erase(m_updateTimes.begin(),it);

		float updateTime = (cur_time - updateStart).GetMilliSeconds();
		m_updateTimes.push_back(std::make_pair(cur_time, updateTime));
	}

	UpdateUpdateTimes(); 
	return !m_bQuit;	
}

bool CSystem::UpdateLoadtime()
{
	m_pPlatformOS->Tick(m_Time.GetRealFrameTime());
	
/*
	// uncomment this code if input processing is required
	// during level loading
	if (m_env.pInput)
	{
		//////////////////////////////////////////////////////////////////////
		//update input system
#ifndef WIN32
		m_env.pInput->Update(true);
#else
		bool bFocus = (GetFocus()==m_hWnd) || m_bEditor;
		{ 
			WriteLock lock(g_lockInput);
			m_env.pInput->Update(bFocus);
			g_BreakListenerTask.m_nBreakIdle = 0;
		}
#endif //WIN32
	}
*/

	return !m_bQuit;	
}

void CSystem::DoWorkDuringOcclusionChecks()
{
	if (g_cvars.sys_deferAudioUpdateOptim && !m_bNoUpdate)
	{
		UpdateAudioSystems();
		m_bNeedDoWorkDuringOcclusionChecks = false;
	}
}

void CSystem::UpdateAudioSystems()
{
	gEnv->GetJobManager()->AddStartMarker("Audio",eTI_Audio);	
	SNTunerAutoMarker::StartMarker(eTI_Audio, "Audio");
	if (m_env.pSoundSystem)
	{
		FRAME_PROFILER( "SysUpdate:Sound",this,PROFILE_SYSTEM );

		// Listener position was already updated above, now we just call the update function
		ESoundUpdateMode UpdateMode = (ESoundUpdateMode)(eSoundUpdateMode_All & ~eSoundUpdateMode_Listeners);
		m_env.pSoundSystem->Update(UpdateMode);
	}

	if (m_env.pMusicSystem)
	{
		FRAME_PROFILER( "SysUpdate:Music",this,PROFILE_SYSTEM );

		m_env.pMusicSystem->Update();
	}
	SNTunerAutoMarker::StopMarker(eTI_Audio);
  gEnv->GetJobManager()->AddStopMarker(eTI_Audio);
}

//////////////////////////////////////////////////////////////////////////
void CSystem::GetUpdateStats( SSystemUpdateStats& stats )
{
	if(m_updateTimes.empty())
	{
		stats = SSystemUpdateStats();
	}
	else
	{
		stats.avgUpdateTime = 0;
		stats.maxUpdateTime = -FLT_MAX;
		stats.minUpdateTime = +FLT_MAX;
		for(std::vector< std::pair<CTimeValue, float> >::const_iterator it = m_updateTimes.begin(), eit = m_updateTimes.end(); it!=eit; ++it)
		{
			const float t = it->second;
			stats.avgUpdateTime += t;
			stats.maxUpdateTime = max(stats.maxUpdateTime, t);
			stats.minUpdateTime = min(stats.minUpdateTime, t);
		}
		stats.avgUpdateTime /= m_updateTimes.size();
	}
}


//////////////////////////////////////////////////////////////////////////
void CSystem::UpdateMovieSystem( const int updateFlags, const float fFrameTime )
{
	if (m_env.pMovieSystem && !(updateFlags&ESYSUPDATE_EDITOR) && g_cvars.sys_trackview)
	{
		float fMovieFrameTime = fFrameTime;

		if (fMovieFrameTime > g_cvars.sys_maxTimeStepForMovieSystem)
			fMovieFrameTime = g_cvars.sys_maxTimeStepForMovieSystem;

		m_env.pMovieSystem->Update(fMovieFrameTime);
	}
}

//////////////////////////////////////////////////////////////////////////
// XML stuff
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
XmlNodeRef CSystem::CreateXmlNode( const char *sNodeName, bool bReuseStrings )
{
	return new CXmlNode( sNodeName, bReuseStrings );
}

//////////////////////////////////////////////////////////////////////////
IXmlUtils* CSystem::GetXmlUtils()
{
	return m_pXMLUtils;
}

//////////////////////////////////////////////////////////////////////////
XmlNodeRef CSystem::LoadXmlFromFile( const char *sFilename, bool bReuseStrings )
{
	LOADING_TIME_PROFILE_SECTION(gEnv->pSystem);



	return m_pXMLUtils->LoadXmlFromFile(sFilename, bReuseStrings);
}

//////////////////////////////////////////////////////////////////////////
XmlNodeRef CSystem::LoadXmlFromBuffer( const char *buffer, size_t size, bool bReuseStrings )
{
	return m_pXMLUtils->LoadXmlFromBuffer(buffer, size, bReuseStrings);
}

//////////////////////////////////////////////////////////////////////////
bool CSystem::CheckLogVerbosity( int verbosity )
{
	if (verbosity <= m_env.pLog->GetVerbosityLevel())
		return true;
	return false;
}

//////////////////////////////////////////////////////////////////////////
void CSystem::Warning( EValidatorModule module,EValidatorSeverity severity,int flags,const char *file,const char *format,... )
{
	va_list args;
	va_start(args,format);
	WarningV( module,severity,flags,file,format,args );
	va_end(args);
}

inline const char* ValidatorModuleToString( EValidatorModule module  )
{
	switch (module)
	{
	case VALIDATOR_MODULE_RENDERER:
		return "Renderer";
	case VALIDATOR_MODULE_3DENGINE:
		return "3DEngine";
	case VALIDATOR_MODULE_AI:
		return "AI";
	case VALIDATOR_MODULE_ANIMATION:
		return "Animation";
	case VALIDATOR_MODULE_ENTITYSYSTEM:
		return "EntitySystem";
	case VALIDATOR_MODULE_SCRIPTSYSTEM:
		return "Script";
	case VALIDATOR_MODULE_SYSTEM:
		return "System";
	case VALIDATOR_MODULE_SOUNDSYSTEM:
		return "Sound";
	case VALIDATOR_MODULE_GAME:
		return "Game";
	case VALIDATOR_MODULE_MOVIE:
		return "Movie";
	case VALIDATOR_MODULE_EDITOR:
		return "Editor";
	case VALIDATOR_MODULE_NETWORK:
		return "Network";
	case VALIDATOR_MODULE_PHYSICS:
		return "Physics";
	case VALIDATOR_MODULE_FLOWGRAPH:
		return "FlowGraph";
	case VALIDATOR_MODULE_ONLINE:
		return "Online";
	}
	return "";
}

//////////////////////////////////////////////////////////////////////////
void CSystem::WarningV( EValidatorModule module,EValidatorSeverity severity,int flags,const char *file,const char *format,va_list args )
{
	// Fran: No logging in a testing environment
	if (m_env.pLog == 0)
	{
		return;
	}

	const char *sModuleFilter = m_env.pLog->GetModuleFilter();
	if (sModuleFilter && *sModuleFilter != 0)
	{
		const char *sModule = ValidatorModuleToString(module);
		if (strlen(sModule) > 1 || CryStringUtils::stristr(sModule,sModuleFilter) == 0)
		{
			// Filter out warnings from other modules.
			return;
		}
	}

	IMiniLog::ELogType ltype = ILog::eComment;
	switch(severity)
	{
	case		VALIDATOR_ERROR		: ltype = ILog::eError;		break;
	case		VALIDATOR_WARNING	: ltype = ILog::eWarning; break;
	case		VALIDATOR_COMMENT	: ltype = ILog::eComment; break;
	default										:													break;
	}
	char szBuffer[MAX_WARNING_LENGTH];
	vsnprintf_s(szBuffer, sizeof(szBuffer), sizeof(szBuffer) - 1, format, args);

	if (file && *file)
	{
		CryFixedStringT<MAX_WARNING_LENGTH> fmt = szBuffer;
		fmt += " [File=";
		fmt += file;
		fmt += "]";

		m_env.pLog->LogWithType( ltype, "%s", fmt.c_str());
	}
	else
		m_env.pLog->LogWithType( ltype, "%s", szBuffer);

	//if(file)
		//m_env.pLog->LogWithType( ltype, "  ... caused by file '%s'",file);

	if (m_pValidator)
	{
		SValidatorRecord record;
		record.file = file;
		record.text = szBuffer;
		record.module = module;
		record.severity = severity;
		record.flags = flags;
		m_pValidator->Report( record );
	}
}



//////////////////////////////////////////////////////////////////////////
void CSystem::Deltree(const char *szFolder, bool bRecurse)
{
	__finddata64_t fd;
	string filespec = szFolder;
	filespec += "*.*";

	intptr_t hfil = 0;
	if ((hfil = _findfirst64(filespec.c_str(), &fd)) == -1)
	{
		return;
	}

	do
	{
		if (fd.attrib & _A_SUBDIR)
		{
			string name = fd.name;

			if ((name != ".") && (name != ".."))
			{
				if (bRecurse)
				{
					name = szFolder;
					name += fd.name;
					name += "/";

					Deltree(name.c_str(), bRecurse);
				}
			}
		}
		else
		{
			string name = szFolder;
			
			name += fd.name;

			DeleteFile(name.c_str());
		}

	} while(!_findnext64(hfil, &fd));

	_findclose(hfil);

	RemoveDirectory(szFolder);
}

//////////////////////////////////////////////////////////////////////////
void CSystem::GetLocalizedPath( const char *sLanguage, string& sLocalizedPath )
{
	// Omit the trailing slash!
	string sLocalizationFolder(string().assign(PathUtil::GetLocalizationFolder(), 0, PathUtil::GetLocalizationFolder().size() - 1));

	if (sLocalizationFolder.compareNoCase("Languages") != 0)
	{
		sLocalizedPath = sLocalizationFolder + "/" + sLanguage + "_xml.pak";
	}
	else
	{
		string const bindRoot = PathUtil::GetGameFolder();
		sLocalizedPath        = bindRoot + "/Localized/" + sLanguage + "_xml.pak";
	}
}

//////////////////////////////////////////////////////////////////////////
void CSystem::GetLocalizedAudioPath( const char *sLanguage, string& sLocalizedPath )
{
	// Omit the trailing slash!
	string sLocalizationFolder(string().assign(PathUtil::GetLocalizationFolder(), 0, PathUtil::GetLocalizationFolder().size() - 1));

	if (sLocalizationFolder.compareNoCase("Languages") != 0)
	{
		sLocalizedPath = sLocalizationFolder + "/" + sLanguage + ".pak";
	}
	else
	{
		string const bindRoot = PathUtil::GetGameFolder();
		sLocalizedPath        = bindRoot + "/Localized/" + sLanguage + ".pak";
	}
}

//////////////////////////////////////////////////////////////////////////
void CSystem::CloseLanguagePak( const char *sLanguage )
{	
	string sLocalizedPath;
	GetLocalizedPath(sLanguage, sLocalizedPath);
	m_env.pCryPak->ClosePacks(sLocalizedPath);
}

//////////////////////////////////////////////////////////////////////////
void CSystem::CloseLanguageAudioPak( const char *sLanguage )
{	
	string sLocalizedPath;
	GetLocalizedAudioPath(sLanguage, sLocalizedPath);
	m_env.pCryPak->ClosePacks(sLocalizedPath);
}

//////////////////////////////////////////////////////////////////////////
void CSystem::Strange()
{
	m_nStrangeRatio += (1 + (100*rand())/RAND_MAX);
}

//////////////////////////////////////////////////////////////////////////
void CSystem::Relaunch(bool bRelaunch)
{
	if (m_sys_firstlaunch)
		m_sys_firstlaunch->Set( "0" );

	m_bRelaunch = bRelaunch;
	SaveConfiguration();
}

//////////////////////////////////////////////////////////////////////////
ICrySizer* CSystem::CreateSizer()
{
	return new CrySizerImpl;
}

//////////////////////////////////////////////////////////////////////////
uint32 CSystem::GetUsedMemory()
{
	return CryMemoryGetAllocatedSize();
}

//////////////////////////////////////////////////////////////////////////
ILocalizationManager* CSystem::GetLocalizationManager()
{
	return m_pLocalizationManager;
}

//////////////////////////////////////////////////////////////////////////
IThreadTaskManager* CSystem::GetIThreadTaskManager()
{
	return m_pThreadTaskManager;
}

//////////////////////////////////////////////////////////////////////////
IResourceManager* CSystem::GetIResourceManager()
{
	return m_pResourceManager;
}

//////////////////////////////////////////////////////////////////////////
void CSystem::debug_GetCallStackRaw(void** callstack, uint32& callstackLength)
{
	uint32 callstackCapacity = callstackLength;
	uint32 nNumStackFramesToSkip = 1;

	memset(callstack, 0, sizeof(void*) * callstackLength);
	callstackLength = 0;

#if defined(WIN32)
	if (callstackCapacity > 0x40)
		callstackCapacity = 0x40;
	callstackLength = RtlCaptureStackBackTrace( nNumStackFramesToSkip,callstackCapacity,callstack,NULL );
#endif
	/*
	static int aaa = 0;
	aaa++;

	if ((aaa & 0xF)  == 0)
	{
	CryLogAlways( "RtlCaptureStackBackTrace = (%d)",callstackLength );
	for (int i=0; i<callstackLength; i++)
	{
	CryLogAlways( "   [%d] = (%X)",i,callstack[i] );
	}
	}

	callstackLength = IDebugCallStack::instance()->CollectCallStackFrames( callstack,callstackCapacity );
	if ((aaa & 0xF)  == 0)
	{
	CryLogAlways( "StackWalk64 = (%d)",callstackLength );
	for (int i=0; i<callstackLength; i++)
	{
	CryLogAlways( "   [%d] = (%X)",i,callstack[i] );
	}
	}
	*/

	if (callstackLength > 0)
	{
		std::reverse(callstack, callstack + callstackLength);
	}
}

//////////////////////////////////////////////////////////////////////////
void CSystem::ApplicationTest( const char *szParam )
{
	assert(szParam);

	if(!m_pTestSystem)
		m_pTestSystem = new CTestSystemLegacy;

	m_pTestSystem->ApplicationTest(szParam);
}

void CSystem::ExecuteCommandLine()
{
	// should only be called once
	{
#ifndef PS3
		static bool bCalledAlready = false;
		assert(!bCalledAlready);
		bCalledAlready=true;
#endif
	}

	// 
	if(gEnv->pCryPak->GetRecordFileOpenList()==ICryPak::RFOM_EngineStartup)
		gEnv->pCryPak->RecordFileOpen(ICryPak::RFOM_Level);
	
	// auto detect system spec (overrides profile settings)
	if (m_pCmdLine->FindArg(eCLAT_Pre,"autodetect"))
		AutoDetectSpec();

	// execute command line arguments e.g. +g_gametype ASSAULT +map "testy"

	ICmdLine *pCmdLine = GetICmdLine();			assert(pCmdLine);

	const int iCnt = pCmdLine->GetArgCount();

	for(int i=0;i<iCnt;++i)
	{
		const ICmdLineArg *pCmd=pCmdLine->GetArg(i);

		if(pCmd->GetType()==eCLAT_Post)
		{
			string sLine = pCmd->GetName();

			if(pCmd->GetValue())
				sLine += string(" ") + pCmd->GetValue();

			GetILog()->Log("Executing command from command line: \n%s\n",sLine.c_str());  // - the actual command might be executed much later (e.g. level load pause)
			GetIConsole()->ExecuteString(sLine.c_str(), false, true);
		}
	}

	//gEnv->pConsole->ExecuteString("sys_RestoreSpec test*"); // to get useful debugging information about current spec settings to the log file
}

void CSystem::DumpMemoryCoverage()
{
	m_MemoryFragmentationProfiler.DumpMemoryCoverage();
}

ITextModeConsole* CSystem::GetITextModeConsole()
{
	if (m_bDedicatedServer)
		return m_pUnixConsole;

	return 0;
}

//////////////////////////////////////////////////////////////////////////
ESystemConfigSpec CSystem::GetConfigSpec( bool bClient )
{
	if (bClient)
	{
		if (m_sys_spec)
			return (ESystemConfigSpec)m_sys_spec->GetIVal();
		return CONFIG_VERYHIGH_SPEC; // highest spec.
	}
	else
		return m_nServerConfigSpec;
}

//////////////////////////////////////////////////////////////////////////
void CSystem::SetConfigSpec( ESystemConfigSpec spec,bool bClient )
{
	if (bClient)
	{
		if (m_sys_spec)
			m_sys_spec->Set( (int)spec );
	}
	else
	{
		m_nServerConfigSpec = spec;
	}
}

//////////////////////////////////////////////////////////////////////////
ESystemConfigSpec CSystem::GetMaxConfigSpec() const
{ 
	return m_nMaxConfigSpec; 
}

//////////////////////////////////////////////////////////////////////////
Crc32Gen* CSystem::GetCrc32Gen()
{
	return CryStringUtils::GetCrc32Gen();
}

//////////////////////////////////////////////////////////////////////////
CPNoise3* CSystem::GetNoiseGen()
{
	static CPNoise3 m_pNoiseGen;	
	return &m_pNoiseGen;
}

//////////////////////////////////////////////////////////////////////
IFlashPlayer* CSystem::CreateFlashPlayerInstance() const
{
	if ( gEnv->pScaleformGFx )
	{
		return gEnv->pScaleformGFx->CreateFlashPlayerInstance();
	}

	return 0;
}

//////////////////////////////////////////////////////////////////////
IFlashPlayerBootStrapper* CSystem::CreateFlashPlayerBootStrapper() const
{
	if ( gEnv->pScaleformGFx )
	{
		return gEnv->pScaleformGFx->CreateFlashPlayerBootStrapper();
	}

	return 0;
}

//////////////////////////////////////////////////////////////////////
void CSystem::SetFlashLoadMovieHandler(IFlashLoadMovieHandler* pHandler) const
{
	if ( gEnv->pScaleformGFx )
	{
		gEnv->pScaleformGFx->SetFlashLoadMovieHandler(pHandler);
	}
}


void CSystem::GetFlashProfileResults(float& accumTime, bool reset) const
{
	if ( gEnv->pScaleformGFx )
	{
		gEnv->pScaleformGFx->GetFlashProfileResults(accumTime, reset);
	}
}

void CSystem::ResetFlashMeshCache() const
{
	if ( gEnv->pScaleformGFx )
	{
		gEnv->pScaleformGFx->ResetFlashMeshCache();
	}
}

#if !defined(RELEASE)
void CSystem::GetFlashRenderStats(unsigned int& numDPs, unsigned int& numTris)
{
	numDPs = 0;
	numTris = 0;

	if ( gEnv->pScaleformGFx )
	{
		gEnv->pScaleformGFx->GetFlashRenderStats( numDPs, numTris );
	}
}
#endif
//////////////////////////////////////////////////////////////////////////
void CProfilingSystem::VTuneResume()
{
#ifdef PROFILE_WITH_VTUNE
	if (VTResume)
	{
		CryLogAlways("VTune Resume");
		VTResume();
	}
#endif
}

//////////////////////////////////////////////////////////////////////////
void CProfilingSystem::VTunePause()
{
#ifdef PROFILE_WITH_VTUNE
	if (VTPause)
	{
		VTPause();
		CryLogAlways("VTune Pause");
	}
#endif
}
//////////////////////////////////////////////////////////////////////////
void CProfilingSystem::StartProfilingX360(const char * fileName)
{






}

//////////////////////////////////////////////////////////////////////////
void CProfilingSystem::StopProfilingX360()
{



}

//////////////////////////////////////////////////////////////////////////
sUpdateTimes& CSystem::GetCurrentUpdateTimeStats()
{
	return m_UpdateTimes[m_UpdateTimesIdx]; 
}

//////////////////////////////////////////////////////////////////////////
const sUpdateTimes* CSystem::GetUpdateTimeStats(uint32& index, uint32& num)
{
	index=m_UpdateTimesIdx; num=NUM_UPDATE_TIMES; return m_UpdateTimes; 
}

void CSystem::UpdateUpdateTimes()
{
	sUpdateTimes& sample = m_UpdateTimes[m_UpdateTimesIdx]; 
	if (m_PhysThread) 
	{ 
		static uint64 lastPhysTime=0U; static uint64 lastMainTime=0U; static uint64 lastYields=0U; static uint64 lastPhysWait=0U; 
		uint64 physTime=0,mainTime=0; uint32 yields=0;
#if EMBED_PHYSICS_AS_FIBER
		if (m_PhysFiber) 
		{ 
			physTime=m_PhysFiber->m_TimeInFiber-lastPhysTime; lastPhysTime=m_PhysFiber->m_TimeInFiber; 
			mainTime=m_PhysFiber->m_TimeYielded-lastMainTime; lastMainTime=m_PhysFiber->m_TimeYielded; 
			yields=m_PhysFiber->m_FiberYields-lastYields; lastYields=m_PhysFiber->m_FiberYields;
		}
#else
		physTime=((CPhysicsThreadTask*)m_PhysThread)->LastStepTaken(); 
		mainTime=CryGetTicks()-lastMainTime; lastMainTime=mainTime;
		lastPhysWait = ((CPhysicsThreadTask*)m_PhysThread)->LastWaitTime(); 
#endif 
		sample.PhysStepTime=physTime;
		sample.SysUpdateTime=mainTime; 
		sample.PhysYields=yields; 
		sample.physWaitTime = lastPhysWait;
	} 
	++m_UpdateTimesIdx; if (m_UpdateTimesIdx>=NUM_UPDATE_TIMES) m_UpdateTimesIdx=0; 
}

void CSystem::EnableEarlyMovieSystemUpdate(bool bEnable)
{
	g_cvars.sys_earlyMovieUpdate = bEnable?1:0;
}

bool CSystem::IsEarlyMovieSystemUpdateOn() const
{
	return g_cvars.sys_earlyMovieUpdate != 0;
}



#include UNIQUE_VIRTUAL_WRAPPER(IProfilingSystem)
//////////////////////////////////////////////////////////////////////
void CSystem::OnLanguageCVarChanged(ICVar * language)
{
	if(language && language->GetType() == CVAR_STRING)
	{
		CSystem* pSys = static_cast<CSystem*>(gEnv->pSystem);
		if(pSys && pSys->GetLocalizationManager())
		{
			const char* lang = language->GetString();

			pSys->CloseLanguagePak(pSys->GetLocalizationManager()->GetLanguage());
			pSys->OpenLanguagePak(lang);
			pSys->GetLocalizationManager()->SetLanguage(lang);
			pSys->GetLocalizationManager()->ReloadData();
		}
	}
}

//////////////////////////////////////////////////////////////////////
void CSystem::OnLanguageAudioCVarChanged(ICVar * language)
{
	if(language && language->GetType() == CVAR_STRING)
	{
		CSystem* pSys = static_cast<CSystem*>(gEnv->pSystem);
		if(pSys)
		{
			const char* lang = language->GetString();

			pSys->CloseLanguageAudioPak(pSys->m_currentLanguageAudio.c_str());
			pSys->OpenLanguageAudioPak(lang);
			pSys->m_currentLanguageAudio = lang;
		}
	}
}

//////////////////////////////////////////////////////////////////////////
void CSystem::OnLocalizationFolderCVarChanged(ICVar* const pLocalizationFolder)
{
	if (pLocalizationFolder && pLocalizationFolder->GetType() == CVAR_STRING)
	{
		CSystem* const pSystem = static_cast<CSystem* const>(gEnv->pSystem);

		if (pSystem != NULL && gEnv->pCryPak != NULL)
		{
			// Reload the localization xmls at the new location.
			ILocalizationManager* const pLocalizationManager = pSystem->GetLocalizationManager();

			if (pLocalizationManager)
			{
				// First release the old localization data.
				pLocalizationManager->ReleaseLocalizationDataByTag(gEnv->bMultiplayer ? "multiplayer" : "singleplayer");
				pLocalizationManager->ReleaseLocalizationDataByTag("init");

				// Close the paks situated in the previous localization folder.
				pSystem->CloseLanguagePak(pLocalizationManager->GetLanguage());
				pSystem->CloseLanguageAudioPak(pSystem->m_currentLanguageAudio.c_str());

				// Set the new localization folder.
				gEnv->pCryPak->SetLocalizationFolder(pLocalizationFolder->GetString());

				// Now open the paks situated in the new localization folder.
				pSystem->OpenLanguagePak(pLocalizationManager->GetLanguage());
				pSystem->OpenLanguageAudioPak(pSystem->m_currentLanguageAudio.c_str());

				// And load the new data.
				pLocalizationManager->LoadLocalizationDataByTag("init");
				pLocalizationManager->LoadLocalizationDataByTag(gEnv->bMultiplayer ? "multiplayer" : "singleplayer");
			}
		}
	}
}

#undef EXCLUDE_UPDATE_ON_CONSOLE

#include UNIQUE_VIRTUAL_WRAPPER(ISystem)
#include UNIQUE_VIRTUAL_WRAPPER(INameTable)


